#include "raknet.client.h"

#include "../RakNetSources/MessageIdentifiers.h"
#include "../RakNetSources/RakPeerInterface.h"
#include "../RakNetSources/RakNetStatistics.h"
#include "../RakNetSources/RakNetTypes.h"

#include <thread>

static bool s_stop_ = false;

raknet_client::raknet_client()
        : peer_(RakNet::RakPeerInterface::GetInstance())
        , usr_data_(0)
{
}

raknet_client::~raknet_client()
{
}

bool raknet_client::connect(const char* host, unsigned short port, char* password, unsigned short client_port)
{
  RakNet::SocketDescriptor socketDescriptor(client_port, 0);
  socketDescriptor.socketFamily = AF_INET;
  peer_->Startup(1, &socketDescriptor, 1);
  peer_->SetOccasionalPing(false);

  if (peer_->Connect(host, port, password, password ? (int)strlen(password) : 0) != RakNet::CONNECTION_ATTEMPT_STARTED) {
    return false;
  }

  s_stop_ = false;
  std::thread thr(std::bind(&raknet_client::run, this));
  thr.detach();
  return true;
}

static unsigned char GetPacketIdentifier(RakNet::Packet *p)
{
  if ((unsigned char)p->data[0] == ID_TIMESTAMP)
  {
    RakAssert(p->length > sizeof(RakNet::MessageID) + sizeof(RakNet::Time));
    return (unsigned char)p->data[sizeof(RakNet::MessageID) + sizeof(RakNet::Time)];
  }

  return (unsigned char)p->data[0];
}
void raknet_client::run()
{
  RakNet::Packet* p;
  unsigned char packetIdentifier;
  for (; !s_stop_; ) {
    std::this_thread::sleep_for(std::chrono::milliseconds(10));

    for (p = peer_->Receive(); p; peer_->DeallocatePacket(p), p = peer_->Receive()) {
      packetIdentifier = GetPacketIdentifier(p);
      switch (packetIdentifier) {
        case ID_CONNECTION_REQUEST_ACCEPTED: {
          if (on_conn_) on_conn_(true, usr_data_);
          break;
        }
        case ID_DISCONNECTION_NOTIFICATION:
        case ID_CONNECTION_LOST: {
          s_stop_ = true;
          if (on_dis_) on_dis_(usr_data_);
          break;
        }
        case ID_CONNECTION_ATTEMPT_FAILED: {
          s_stop_ = true;
          if (on_conn_) on_conn_(false, usr_data_);
          break;
        }
        default: {
          if (!on_recv_) {
            s_stop_ = true;
            break;
          }
          if (!on_recv_(packetIdentifier, p->data + sizeof(RakNet::MessageID), p->length - sizeof(RakNet::MessageID), usr_data_)) {
            s_stop_ = true;
            break;
          }
          break;
        }
      }
    }
  }
}
